using System;
using System.Collections;
using System.Collections.Generic;
using Cinemachine;
using Kayac;
using Kayac.HyperCasual;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;
public enum GameStatus
{
	Playing,
	Pause,
	GameComplete,
	GameFail
}
public struct mypanel
{
	public Vector3 position;
	public Vector3 normal;

	public mypanel(Vector3 pos, Vector3 norm)
	{
		position = pos;
		normal = norm;
	}
}
public class Main : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IPointerUpHandler
{
	public GameStatus gameStatus;
	private class HitStopRequest
	{
		public float power;

		public float timer;
	}
	public Material cross;
	[SerializeField]
	private Player.Settings playerSettings;

	[SerializeField]
	private CinemachineVirtualCamera vcam1;
	[SerializeField]
	private CinemachineVirtualCamera vcam2;
	[SerializeField]
	private PlayableDirector director;

	[SerializeField]
	private ParticleRenderer.Settings particleSettings;

	[SerializeField]
	private float lineWidth;

	[SerializeField]
	private int targetDetectionIteration;

	[SerializeField]
	private float defaultTargetDistance;

	[SerializeField]
	private LevelComplete levelComplete;
	[SerializeField]
	private LevelFailure levelFail;

	[SerializeField]
	private FullScreenInputHandler inputHandler;

	[SerializeField]
	private CpiTestKit cpiTestKit;
	[SerializeField]
	private LineRenderer lineRenderer;

	[SerializeField]
	private Camera mainCamera;

	[SerializeField]
	private ParticleRenderer particleRenderer;

	[SerializeField]
	private PhysicCameraController cameraController;

	[SerializeField]
	private Transform uiFingerTip;

	[SerializeField]
	private Text failMessage;

	[SerializeField]
	private Transform targetCursor;

	[SerializeField]
	private Light defaultLight;

	[SerializeField]
	private Volume globalVolume;

	private const string DefaultBulletName = "Shuriken";

	public Level level;

	private int? levelMoveRequest;

	private bool coLevelRunning;

	private Vector2 dragBeginPointer;

	private SimpleThreadPool threadPool;

	private bool prevPointerDown;

	public SaveData saveData;

	private int currentLevelIndex;

	public LevelTableAsset levelTableAsset;
	private LevelTable levelTable;
	private BulletBase bulletPrefab;

	private LightingSceneLoader lightingSceneLoader;

	private Dictionary<string, Material> materialSet = new Dictionary<string, Material>();

	private Level.Settings levelSettings;

	private float hitStopPower;

	private float fixedTime;

	private List<HitStopRequest> hitStopRequests;

	private List<Vector3> cameraPointsTmp;

	private float fovGoal;

	private float fovDefault;

	private Vector2[] pointerHistory;

	private int pointerHistoryNext;

	private float avgDeltaTime;

	private ColorAdjustments colorAdjustments;
	[SerializeField] private Vector3 StartPos;
	[SerializeField] private Vector3 EndPos;
	[SerializeField] private Vector3 WorldStartPos;
	[SerializeField] private Vector3 WorldEndPos;
	public bool isDrawing;
	[SerializeField] private float drawDistance = 10f; // 绘制距离摄像机的距离
	public float SlicePrecision = 6;
	float near = 0f;
	ButtonPointerHandler buttonPointerHandler = new ButtonPointerHandler();
	public static Main Instance
	{
		get
		{
			return FindObjectOfType<Main>();
		}
		private set
		{

		}
	}
	public Player player
	{
		get
		{
			if (level != null)
			{

				return level.Player;
			}
			return null;
		}
	}
	private float saturation = -50f; // 饱和度值范围：-100（完全去色）到 100（高度饱和）
	public float Saturation
	{
		get { return saturation; }
		set
		{
			if (value > 100f)
			{
				value = 100f;
			}
			else if (value < -100f)
			{
				value = -100f;
			}
			saturation = value;
			if (colorAdjustments != null)
			{
				colorAdjustments.saturation.value = saturation;
			}
		}
	}
	private Vector3 cameraOriginPos;
	private Vector3 cameraOriginRot;
	private Vector3 vcam1OriginPos;
	private Vector3 vcam2OriginPos;
	private Vector3 vcam1OriginRot;
	private Vector3 vcam2OriginRot;
	private void Awake()
	{
		if (globalVolume != null)
		{
			globalVolume.profile.TryGet<ColorAdjustments>(out colorAdjustments);
		}
		if (vcam1 != null)
		{
			vcam1OriginPos = vcam1.transform.position;
			vcam1OriginRot = vcam1.transform.rotation.eulerAngles;
		}
		if (vcam2 != null)
		{
			vcam2OriginPos = vcam2.transform.position;
			vcam2OriginRot = vcam2.transform.rotation.eulerAngles;
		}
		cameraOriginPos = mainCamera.transform.position;
		cameraOriginRot = mainCamera.transform.rotation.eulerAngles;
		near = mainCamera.nearClipPlane;
		lineRenderer.startWidth = lineWidth;
		lineRenderer.endWidth = lineWidth;
		saveData = null;
		StorageManager.Instance.Load<SaveData>(Const.SaveDataName, ref saveData);
		if (levelTableAsset == null)
		{
			UnityEngine.Debug.LogError("关卡数据为空");
			return;
		}
		levelTable = levelTableAsset.levelTable;
		if (saveData == null)
		{
			saveData = new SaveData();
			saveData.SetUsingBulletName(levelTable.GetBulletPrefabName());
			StorageManager.Instance.Save<SaveData>(Const.SaveDataName, saveData);
		}

	}
	private void Start()
	{

		bulletPrefab = levelTable.LoadBulletPrefab(saveData.UsingBulletName);
		if (levelSettings == null)
		{
			levelSettings = levelTable.CreateLevelSettings();
		}
		List<Material> materials = ResourceManager.Instance.LoadAllRes<Material>("materials/" + levelTable.GetColorSettings().MaterialSetName);
		foreach (Material material in materials)
		{
			materialSet.Add(material.name, material);
		}
		LoadLevel();
		levelComplete.step1 = DestoryOldScene;
		levelComplete.step2 = CreateNewScene;
		levelFail.step1 = DestoryOldScene;
		levelFail.step2 = CreateNewScene;
	}
	private void CoLevel()
	{
		gameStatus = GameStatus.Pause;
		saveData.IncrementLevelIndex();
		levelComplete.gameObject.SetActive(true);
		levelComplete.ShowPanel();
	}
	public void GameOver()
	{
		gameStatus = GameStatus.Pause;
		levelFail.gameObject.SetActive(true);
		levelFail.ShowPanel();

	}
	public void DestoryOldScene()
	{
		DestroyImmediate(level.gameObject);
		level = null;
	}
	public void CreateNewScene()
	{
		LoadLevel();
		VcamReset();
		UpdateCameraGoal();

	}
	public void VcamReset()
	{
		vcam1.Follow = null;
		vcam1.LookAt = null;
		vcam1.transform.position = vcam1OriginPos;
		vcam1.transform.rotation = Quaternion.Euler(Vector3.zero);
		vcam2.Follow = null;
		vcam2.LookAt = null;
		vcam2.transform.position = vcam2OriginPos;
		vcam2.transform.rotation = Quaternion.Euler(Vector3.zero);
		mainCamera.transform.position = cameraOriginPos;
		mainCamera.transform.rotation = Quaternion.Euler(cameraOriginRot);
	}
	private void LoadLevel()
	{
		level = levelTable.Instantiate(saveData.LevelIndex, transform.root);
		level.ManualStart(this, playerSettings, bulletPrefab, levelSettings, materialSet);
	}
	private void Update()
	{
		if (buttonPointerHandler.GetData() != null && buttonPointerHandler.IsUp())
		{
			OnPointerUp(buttonPointerHandler.GetData());
		}
		if (gameStatus == GameStatus.Playing)
		{
			near = mainCamera.nearClipPlane;
			if (isDrawing)
			{
				EndPos = Input.mousePosition;
				lineRenderer.SetPosition(1, mainCamera.ScreenToWorldPoint(new Vector3(EndPos.x, EndPos.y, near + drawDistance)));
			}
			UpdateCameraGoal();
			level.ManualUpdate(Time.deltaTime);
		}
		else if (gameStatus == GameStatus.GameComplete)
		{
			AudioManager.Instance.PlayOnShot((int)ClipType.zuihouyiji);
			CoLevel();
		}
		else if (gameStatus == GameStatus.GameFail)
		{
			AudioManager.Instance.PlayOnShot((int)ClipType.shibai);
			GameOver();
		}
		else
		if (gameStatus == GameStatus.Pause)
		{
			level.ForceClear();
		}
	}
	private void FixedUpdate()
	{
		if (gameStatus == GameStatus.Playing)
		{
			fixedTime = Time.deltaTime;
			level.ManualFixedUpdate(fixedTime, true, Vector2.zero);
			TryFire(fixedTime);
		}
	}

	public static T GetOwner<T>(Transform node)
	{
		return default(T);
	}

	public float DistanceFromCamera(Vector3 p)
	{
		return 0f;
	}
	public void PlayCollisionSound(Vector3 position, float speed, float mass, SoundMaterial material)
	{
	}
	public void OnHitEnemy(float damage, Enemy.DamageType damageType)
	{
		if (damage > 0.5f && damageType != Enemy.DamageType.Deflect)
		{
			StartCoroutine(BulletTime());
		}
	}
	float Timer = 0f;
	float TimeInterval = 0.125f;
	IEnumerator BulletTime()
	{
		Main.Instance.Saturation = -50f;
		while (Timer < TimeInterval)
		{
			Time.timeScale = Mathf.Lerp(1f, 0.1f, Timer / TimeInterval);
			Timer += Time.deltaTime;
			yield return null;
		}
		Timer = 0f;
		while (Timer < TimeInterval)
		{
			Time.timeScale = Mathf.Lerp(0.1f, 1f, Timer / TimeInterval);
			Timer += Time.deltaTime;
			yield return null;
		}
		Main.Instance.Saturation = 0f;
	}
	float timeInterval = 0.2f;
	float timer = 0f;
	bool isUp = false;
	private void TryFire(float deltaTime)
	{
		timer += deltaTime;
		if (isUp && (timer > timeInterval))
		{
			Fire(WorldStartPos, WorldEndPos, StartPos, EndPos);
			timer = 0f;
			isUp = false;
		}
	}
	Ray ray;
	private void Fire(Vector3 p0, Vector3 p1, Vector3 sp0, Vector3 sp1)
	{
		float near = mainCamera.nearClipPlane;
		Vector3 line = p1 - p0;
		EnemyPart enemyPart = null;
		Vector3 localPos = Vector3.zero;
		int middle = (int)SlicePrecision / 2;
		for (float i = middle; i < SlicePrecision; i++)
		{
			ray = mainCamera.ScreenPointToRay(Vector3.Lerp(sp0, sp1, i / SlicePrecision));
			if (Physics.Raycast(ray, out RaycastHit hit))
			{
				if (enemyPart == null)
				{
					enemyPart = hit.collider.GetComponentInParent<EnemyPart>();
					defaultTargetDistance = Vector3.Distance(ray.origin, hit.point);
					if (enemyPart != null)
					{
						localPos = enemyPart.transform.InverseTransformPoint(hit.point);
						break;
					}
				}
			}
			ray = mainCamera.ScreenPointToRay(Vector3.Lerp(sp0, sp1, (SlicePrecision - i) / SlicePrecision));
			if (Physics.Raycast(ray, out hit))
			{
				if (enemyPart == null)
				{
					enemyPart = hit.collider.GetComponentInParent<EnemyPart>();
					defaultTargetDistance = Vector3.Distance(ray.origin, hit.point);
					if (enemyPart != null)
					{
						localPos = enemyPart.transform.InverseTransformPoint(hit.point);
						break;
					}
				}
			}
		}

		if (enemyPart == null)
		{
			ray = mainCamera.ScreenPointToRay(Vector3.Lerp(sp0, sp1, 0.5f));
			defaultTargetDistance = 64f;
		}
		level.Player.Fire(enemyPart, localPos, ray.direction, line, level.Player.transform, particleRenderer, Vector3.Distance(sp0, sp1), ray.origin, defaultTargetDistance);
	}
	private void UpdateCameraGoal()
	{
		if (mainCamera == null)
		{
			return;
		}
		float distance = float.MaxValue;
		CinemachineBrain brain = Camera.main.GetComponent<CinemachineBrain>();
		if (distance > 3f)
		{
			vcam1.LookAt = (level.FindNearestEnemy(out distance, player.transform.position) as Enemy)?.transform.Find("Hips");
			BlendToCamera(vcam1, 2f);
			if (distance <= 3f)
			{
				vcam2.Follow = level.Player.HipsTransform;
				vcam2.LookAt = level.Player.HipsTransform;
				BlendToCamera(vcam2, 2f);
			}
		}
	}
	public void BlendToCamera(CinemachineVirtualCameraBase targetCamera, float blendTime = 2f)
	{
		var blendDef = new CinemachineBlendDefinition(
			CinemachineBlendDefinition.Style.EaseInOut,
			blendTime
		);
		targetCamera.Priority = 10;
		foreach (var cam in FindObjectsOfType<CinemachineVirtualCameraBase>())
		{
			if (cam != targetCamera) cam.Priority = 0;
		}
	}
	public void OnPointerDown(PointerEventData eventData)
	{
		buttonPointerHandler.SetData(eventData);
		if (gameStatus != GameStatus.Playing)
		{
			return;
		}
		lineRenderer.positionCount = 2;
		isDrawing = true;
		StartPos = Input.mousePosition;
		WorldStartPos = mainCamera.ScreenToWorldPoint(new Vector3(StartPos.x, StartPos.y, near + drawDistance));
		lineRenderer.SetPosition(0, mainCamera.ScreenToWorldPoint(new Vector3(StartPos.x, StartPos.y, near + drawDistance)));
		AudioManager.Instance.PlayOnShot((int)ClipType.dianji);
	}

	public void OnPointerUp(PointerEventData eventData)
	{
		buttonPointerHandler.ClearData();
		isDrawing = false;
		isUp = true;
		lineRenderer.positionCount = 0;
		EndPos = Input.mousePosition;
		WorldEndPos = mainCamera.ScreenToWorldPoint(new Vector3(EndPos.x, EndPos.y, near + drawDistance));
	}

}
